/**
 * Classe contenant les ascenseurs, et permettant la configuration de leur positionnement d'origine
 * @authors: Bertrand GUILLAUMOND, Nicolas BOUQUIN
 * @version 1.0
 */

import java.util.*;

public class Building{
	final float ELEVATOR_COUNT = 6;
	final float HOTEL_PRIORITY = 3;
	final float OFFICES_PRIORITY = 1;
	final float COMPANY_PRIORITY = 2;
	final float INFINITE = 999999999;
	private Elevator[] elevators = new Elevator[6];
	ElevatorPanel[] elevatorPanels = new ElevatorPanel[6];
	Gui Interface;
	Config conf;
	
	ConsoleFrame console;

	public Building(ConsoleFrame c, Config co)
	{
		Random rand = new Random();
		for(int i = 0; i < ELEVATOR_COUNT;i++){
			int floor = rand.nextInt(44);
			
			elevators[i] = new Elevator(/*floor*/ 4,elevatorPanels[i], c);
			elevatorPanels[i] = new ElevatorPanel(0,elevators[i]);
			elevators[i].setPanel(elevatorPanels[i]);
		}
		console = c;
		conf = co;
		Interface = new Gui(elevatorPanels);
	}

	public Config getConfiguration()
	{
		return conf;
	}

	public void calculateBackPosition()
	{
		switch(conf.getReturnMode()){
			case 0: // Normal
				for (int i = 0; i <6; i++)
					elevators[i].setOrigin(4);
				break;
			case 1: // Zone
					elevators[0].setOrigin(4); 
					elevators[1].setOrigin(25); 
					elevators[2].setOrigin(39); 
					elevators[3].setOrigin(0);
					elevators[4].setOrigin(31);
					elevators[5].setOrigin(42);
				break;
			case 2: // Optimisé
                if(conf.isDay() && conf.isWeek())
                {
					elevators[0].setOrigin(20); 
					elevators[1].setOrigin(23); 
					elevators[2].setOrigin(16); 
					elevators[3].setOrigin(39);
					elevators[4].setOrigin(4);
					elevators[5].setOrigin(4);
                }
                else
                {
                    elevators[0].setOrigin(4); 
					elevators[1].setOrigin(39); 
					elevators[2].setOrigin(2); 
					elevators[3].setOrigin(41);
					elevators[4].setOrigin(4);
					elevators[5].setOrigin(31);   
                }	
                break;
		}
	}
	
	public void callElevator(Customer c,int from, int to)
	{
		//System.out.println("Building.callElevator()");
		Elevator ev = getElevator(from, to);
		ev.addCaller(c);
		/*if(ev.getNbUsers() == 0)
			ev.go(from);*/
	}

	public Elevator[] getElevators()
	{
		return elevators;
	}
	
	public ElevatorPanel[] getPanels()
	{
		return elevatorPanels;
	}
	
	public Gui getInterface()
	{
		return Interface;
	}

	public float getPriorityCoefficient(Elevator e, int floor)
	{
		float coeff;
		switch(conf.getEnergyMode())
		{
			case 0: coeff = e.getEnergyTo(floor);
				break;
			case 1: coeff = e.getDistanceTo(floor);
				break;
			case 2: coeff = e.getDistanceTo(floor)*e.getEnergyTo(floor);
				break;
			default: coeff = e.getDistanceTo(floor)*e.getEnergyTo(floor);
				break;
		}

		return coeff;
	}
	
	public Elevator getElevator(int floor, int to)
	{
		Vector<Elevator> candidates = new Vector<Elevator>();
		int min;
		//if(true)
		//	return elevators[0];
		Elevator selected;
		selected = getDirect(floor);
		if(selected != null)
			return selected;
		else
		{		//System.out.println("Les candidats sont: ");
				// on cherche un ascenseur dans le bon sens
				if(floor < to) // on monte
				{
					for(int i = 0 ; i < 6 ;i ++)
					{
						//if(elevators[i].isUpping())
							//System.out.println("l'asc" + i + "monte");
						if(((elevators[i].isUpping() && elevators[i].canStopTo(floor)) || elevators[i].isIdle()) && !elevators[i].isFull())
						{
							//System.out.print("\t"+i);
							candidates.add(elevators[i]);
						}
					}
					//System.out.print("\n");
				}
				else
				{
					for(int i = 0 ; i < 6 ;i ++)
					{
						if(((!elevators[i].isUpping() && elevators[i].canStopTo(floor)) || elevators[i].isIdle()) && !elevators[i].isFull())
						{
							//System.out.print("\t"+i);
							candidates.add(elevators[i]);
						}
					}
				}
	
			//
			float[] coeff = new float[candidates.size()];
			for(int i = 0;	 i < candidates.size(); i++)
			{
				coeff[i] = getPriorityCoefficient(candidates.get(i), floor);
				//System.out.print("\t "+ coeff[i]);
			}

			min = 0;
			boolean ok = true;
			for(int i = 0; i < candidates.size(); i++)
			{
				if(coeff[i] < coeff[min])
					min = i;
			}
			//System.out.println("Min 1: "+min);
			if(candidates.size() > 0) // si ya des candidats
			{
				while (!candidates.get(min).canStopTo(floor))
				{
					if(min < candidates.size() - 1)
						min++;
					else{
						ok = false;
						min = getNearest(floor); // hacky correction
						break;				
					}
				}
				if(ok)
					selected = candidates.get(min);
				else
					selected = elevators[min];
			}
			else
			{
				min = getNearest(floor);
				selected = elevators[min];
			}
			
			
			//console.append("L'ascenseur "+min + " est selectionné pour aller à l'étage "+(floor -4));
			candidates.clear();
			return selected;	
		}
	}

	public int getNearest(int floor)
	{
		System.out.println("Aucun ascenseur trouvé, on prend le plus proche");
		float[] coeff = new float[6];
		int min;
		for(int i = 0;	 i < 6; i++)
		{
			if(!elevators[i].isFull())
				coeff[i] = elevators[i].getDistanceTo(floor);
			else
				coeff[i] = INFINITE;
		}
		min = 0;
		for(int i = 0; i < 6; i++)
		{
			if(coeff[i] < coeff[min])
					min = i;
		}

		return min;
	}
	
	public Elevator getDirect(int floor)
	{
		Elevator direct;
		for(int i = 0; i < ELEVATOR_COUNT;i++){
			if((elevators[i]).getFloor() == floor && !(elevators[i]).isFull())
				return elevators[i];
		}

		return null;
	}
	
	public void refresh(){
		for(int i = 0; i < 6; i++)
		{
			elevators[i].getStatistics().incrementExecutionTime();
			elevators[i].refresh();
		}
	
	}
}
